#include "MainWindow.h"
#include "../Geometries/PointCloud.h"
#include "../Geometries/PolygonMesh.h"
#include "../Operations/OP_Translate.h"

#include <fstream>
#include <sstream>

#include <QtXml>

using namespace std;
using namespace CICore;
using namespace CIGeom;
using namespace CIView;
using namespace CIOps;

///<************************************************************************************************************>
///<************************************* region CONSTANTS DEFINITION ******************************************>
///<************************************************************************************************************>

const QString CIGui::MainWindow::STYLE_SHEET = QString (
                                                            "QObject {"
                                                                "font-family: sans-serif;"
                                                                //"font: Helvetica;"
                                                                "font-size: 9pt;"

                                                                "color: #333;"
                                                            "}"

                                                            "QMainWindow {"
                                                                "background-color: rgb(240,240,240);"
                                                            "}"

                                                            "QMenu {"
                                                                + GENERAL_BACKGROUND +
                                                            "}"

                                                            "QMenu::item:selected {"
                                                                "color: black;"
                                                            "}"

                                                            "QMenuBar {"
                                                                "border-radius: 10px;"
                                                                "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
                                                                                                   "stop: 0 #dadbde, stop: 1 #f6f7fa);"
                                                            "}"


                                                            "QMenuBar::item  {"
                                                                "background-color: transparent;"
                                                            "}"

                                                            "QMenuBar::item:pressed {"
                                                                "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
                                                                                                   "stop: 0 #f6f7fa, stop: 1 #dadbde);"
                                                            "}"

                                                            "QMenuBar::item:selected {"
                                                                "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
                                                                                                   "stop: 0 #f6f7fa, stop: 1 #dadbde);"                                                                                                                                                                   
                                                            "}"

                                                            "QToolBar, QStatusBar {"
                                                                + GENERAL_BORDER +
                                                                "border-radius: 10px;"
                                                                + GENERAL_BACKGROUND +
                                                                "spacing: 2px;" /* spacing between items in the tool bar */
                                                            "}"

                                                            "QToolBar::handle {"
                                                                 "image: url("+ IMAGES_FOLDER +"handle.png);"
                                                                 "width: 5px;"
                                                                 "height: 5px;"
                                                                 "margin: 1px 2px 1px 2px;"
                                                            "}"

                                                            "QToolBar:separator {"
                                                                "width: 1px;"
                                                                "height: 1px;"
                                                                "background: lightgray;"
                                                                "margin: 2px 2px 2px 2px;"
                                                            "}"

                                                            "QToolButton:pressed, QToolButton:checked, QToolButton:selected {"
                                                                "border: 1px inset #aaa;"
                                                                "border-radius: 5px;"
                                                                "background-color: qlineargradient(spread:reflect, x1:0.062,"
                                                                                                "y1:0.0170455, x2:0.562955, y2:0.392,"
                                                                                                "stop:0 #bbf, stop:1 rgba(255, 255, 255, 255));"
                                                                "padding: 2px 1px 0px 2px;"
                                                            "}"

                                                            "QToolButton:checked, QToolButton:selected {"
                                                                "border: 1px inset gray;"
                                                                "border-radius: 5px;"
                                                            "}"

                                                            "QToolButton:hover:!checked:!pressed {"
                                                                "border: 1px solid #aaa;"
                                                                "border-radius: 5px;"
                                                                "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
                                                                            "stop: 0 #eef, stop: 0.4 #DDDDDD,"
                                                                            "stop: 0.5 #D8D8D8, stop: 1.0 #bbf);"
                                                            "}"

                                                            "QToolTip {"
                                                                "border: 0px solid gray;"
                                                                "border-radius: 0px;"
                                                                "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
                                                                                                "stop: 0 #f6f7fa, stop: 1 #dadbde);"
                                                            "}"


                                                            + TABS_STYLE_SHEET +

                                                            "QFrame {"
                                                                + GENERAL_BORDER +
                                                                "border-radius: 20px;"
                                                                + GENERAL_BACKGROUND +
                                                            "}"

                                                            //"QProgressDialog {"
                                                            //   + GENERAL_BORDER +
                                                            //   //"border-style: solid;"
                                                            //   "border-radius: 20px;"
                                                            //   + GENERAL_BACKGROUND +
                                                            //"}"



                                                    //TODO -> Restore materials controls and remove the following QTabBar style
                                                    "QTabBar::tab {"
                                                        "padding: 2px 90px 2px 96px;"
                                                        "margin: 0px 2px 0px 2px;"
                                                    "}"


                                                            );
/***************************************************************************************************************
************************************** endregion CONSTANTS DEFINITION ******************************************
****************************************************************************************************************/






/// <summary>
/// Constructor
/// </summary>
/// <param name="parent"> The widget parent </param>
CIGui::MainWindow::MainWindow (QWidget *parent)
: QMainWindow (parent), views(4), operationManager (views) {
    //setMinimumSize (820, 500);        //Sets the window's minimum size

    CreateActions();                //Creates the actions
    CreateLayouts();                //Creates the window's layouts
    CreateContent();                //Creates the window's content widget
    CreateMenus();                  //Creates the window's menus
    CreateStatusBar();              //Creates the window's status bar
    CreateToolbars();               //Creates the window's toolbars
    CreateViews();                  //Creates the gl view
    CreateControlsTab();            //Creates the controls tab
    CreateModelingControls();       //Creates the modeling controls
    CreateMaterialsControls();      //Creates the materials'controls

    setWindowTitle (tr ("Creative Interaction 3D"));        //Sets the window's title
    setStyleSheet (STYLE_SHEET);

    //QSettings settings ("CreativeInteraction", "CI3D");
    //restoreGeometry (settings.value("geometry").toByteArray());
    //restoreState (settings.value("windowState").toByteArray());
}

/// <summary>
/// Destructor
/// </summary>
CIGui::MainWindow::~MainWindow() {
    //Deleting content and all its children
    delete content;                   //Deletes the window's content and its children

    //Deleting Menus
    delete fileMenu;                  //Deletes the file menu
    delete editMenu;                  //Deletes the edit menu
    delete viewMenu;                  //Deletes the view menu
    delete toolsMenu;                 //Deletes the tools menu
    delete helpMenu;                  //Deletes the help menu

    //Deleting Toolbars
    delete operationsToolBar;         //Deletes the file toolbar
    delete editToolBar;               //Deletes the edit tollbar

    //Deleting Actions
    delete newAct;                    //Deletes the new action
    delete openAct;                   //Deletes the open action
    delete saveAct;                   //Deletes the save action
    delete saveAsAct;                 //Deletes the "save as" action
    delete aboutAct;                  //Deletes the about action
    delete quitAct;                   //Deletes the quit action
    delete undoAct;                   //Deletes the undo action
    delete redoAct;                   //Deletes the redo action
    delete deleteAct;                 //Deletes the delete action
    delete duplicateAct;              //Deletes the duplicate action
    delete selectAllAct;              //Deletes the "select all" action
    delete deselectAllAct;            //Deletes the "deselect all" action
    delete invertSelectionAct;        //Deletes the "invert selection" action
    delete hideAct;                   //Deletes the hide action
    delete unhideAct;                 //Deletes the unhide action

    //Deleting operations'Actions
    delete operationsActionGroup;     //Deletes the group of action connencted with operations
    delete cameraControlAct;          //Deletes the camera control action
    delete selectGeometriesAct;       //Deletes the select geometries action
    delete selectVerticesAct;         //Deletes the select vertices action
    delete selectFacesAct;            //Deletes the select faces action
    delete translateAct;              //Deletes the translate action
    delete scaleAct;                  //Deletes the scale action
    delete rotateAct;                 //Deletes the rotate action
    delete extrudeAct;                //Deletes the extrude action
    delete createVertexAct;           //Deletes the create vertex action
    delete createTriangleAct;         //Deletes the create triangle action
    //delete createTriangleStripAct;    //Deletes the create triangle strip action
    delete createRectangleAct;        //Deletes the create rectangle action
    delete createCuboidAct;           //Deletes the create cuboid action
    delete createSphereAct;           //Deletes the create sphere action
    delete createCylinderAct;         //Deletes the create cylinder action
    delete createConeAct;             //Deletes the create cone action
    delete createTorusAct;            //Deletes the create torus action
}






///<************************************************************************************************************>
///<****************************************** region Public SLOTS *********************************************>
///<************************************************************************************************************>

/// <summary>
/// Slot method called to show the about box
/// </summary>
void CIGui::MainWindow::About() {                                        //TODO -> Look at actions and slots again
    QMessageBox::about (0, tr ("About Creative Interaction 3D"), "<html>"
                                                                     "<head>"
                                                                         "<style type=\"text/css\">"
                                                                            "body {"
                                                                                "background-color: white;"
                                                                            "}"
                                                                         "</style>"
                                                                     "</head>"
                                                                     "<body>"
                                                                         "<center><h2>Creative Interaction 3D<br/>version 1.0</h2></center>"
                                                                         "<center><img src=\""+IMAGES_FOLDER+"camera-black.png\"></center>"
                                                                         "<p>"
                                                                             "Creative Interaction 3D (CI3D) "
                                                                             "is an OpenGL-based 3D model editor. "
                                                                             "<br/>It supports simple mesh creation "
                                                                             "and trasnformation, and multi-level "
                                                                             "undo-redo."
                                                                         "</p>"
                                                                     "</body>"
                                                                 "</html>");/*tr ());*/
}

/// <summary>
/// Slot method called to create a new scene
/// </summary>
void CIGui::MainWindow::New(){
    if (!(scene.saved)) {                                                       //If the current scene has not been saved
        int response = QMessageBox::question (0,                                //shows a message box, asking to the user if he want to save the scene
                                   "CI3D",
                                   "Do you want to save the current scene?",
                                   "Yes",
                                   "No",
                                   "Cancel",
                                   2);

        switch (response) {
            case 0: //Yes
                Save();             //if the user answer is Yes, saves the scene
                break;

            case 2: //Cancel
                return;             //if the user answer is Cancel, must return
        }
    }


    scene = Scene();                                    //Creates a new scene

    currentFileName =  QString();

    operationManager.Reset();                           //Resets the operation manager

    //Disabling all useless actions
    undoAct->setDisabled (true);
    redoAct->setDisabled (true);
    deleteAct->setDisabled (true);
    duplicateAct->setDisabled (true);
    translateAct->setDisabled (true);
    scaleAct->setDisabled (true);
    rotateAct->setDisabled (true);
    extrudeAct->setDisabled (true);

    UpdateViews();                                      //Updates the GL views
}

/// <summary>
/// Slot method called to open a saved scene
/// </summary>
void CIGui::MainWindow::Open(){
    if (!(scene.saved)) {                                                       //If the current scene has not been saved
        int response = QMessageBox::question (0,                                //shows a message box, asking to the user if he want to save the scene
                                   "CI3D",
                                   "Do you want to save the current scene?",
                                   "Yes",
                                   "No",
                                   "Cancel",
                                   2);

        switch (response) {
            case 0: //Yes
                Save();             //if the user answer is Yes, saves the scene
                break;

            case 2: //Cancel
                return;             //if the user answer is Cancel, must return
        }
    }                                                       //if the user answer is yes, save the scene


    currentFileName =  QFileDialog::getOpenFileName (0,                          //Opens a file dialog, asking for the filename to open
                                                      tr("Open Scene"),
                                                      QDir::currentPath(),
                                                      tr("CI3D Files (*.ci3d)"));

    if (currentFileName.isEmpty())                      //If the user has canceled the operation
        return;                                         //must return

    if (!(scene.GetGeometries().empty()))               //If the old scene is not empty
        scene = Scene();                                //must create a new one

    operationManager.Reset();                           //Resets the operation manager

    //Disabling all useless actions
    undoAct->setDisabled (true);
    redoAct->setDisabled (true);
    deleteAct->setDisabled (true);
    duplicateAct->setDisabled (true);
    translateAct->setDisabled (true);
    scaleAct->setDisabled (true);
    rotateAct->setDisabled (true);
    extrudeAct->setDisabled (true);

    if (LoadSceneFromCI3D (currentFileName)) {                  //If the load operation succed
        statusBar()->showMessage (tr("Scene loaded"), 2000);    //shows a message in the status bar
        scene.saved = true;
        scene.DeselectAllFaces();
    }

    UpdateViews();                                      //Updates the GL views
}
/// <summary>
/// Slot method called to save the current scene
/// </summary>
void CIGui::MainWindow::Save(){
    if (scene.saved)            //If the scene has been already saved
        return;                 //must return

    if (currentFileName.isEmpty()) {                                                    //If is the first saving action
        currentFileName =  QFileDialog::getSaveFileName (0,                             //opens a file dialog, asking for the filename to open
                                                         tr("Save Scene"),
                                                         QDir::currentPath(),
                                                         tr("CI3D Files (*.ci3d)"));

        if (currentFileName.isEmpty())                                                  //if the user has canceled the operation
            return;                                                                     //must return
    }

    QFile file (currentFileName);                           //Retrieves the file indientified by the file name selected by the user

    if (!file.open(QFile::WriteOnly | QFile::Text)) {       //If there are problems opening this file
        QMessageBox::warning (0, tr("CI3D"),
            tr("Cannot write file %1:\n%2.")
            .arg (currentFileName)
            .arg (file.errorString()));
        return;                                             //must return
    }

    file.close();

    SaveSceneAsCI3D (currentFileName);                      //Saves the scene as a CI3D file
    statusBar()->showMessage (tr("Scene saved"), 2000);     //Shows a message in the status bar
}

/// <summary>
/// Slot method called to save the current scene
/// </summary>
void CIGui::MainWindow::SaveAs(){
    currentFileName =  QFileDialog::getSaveFileName (0,                             //Opens a file dialog, asking for the filename to open
                                                     tr("Save Scene"),
                                                     QDir::currentPath(),
                                                     tr("CI3D Files (*.ci3d)"));

    if (currentFileName.isEmpty())                                                  //If the user has canceled the operation
        return;                                                                     //must return

    QFile file (currentFileName);                           //Retrieves the file indientified by the file name selected by the user

    if (!file.open(QFile::WriteOnly | QFile::Text)) {       //If there are problems opening this file
        QMessageBox::warning (0, tr("CI3D"),
            tr("Cannot write file %1:\n%2.")
            .arg (currentFileName)
            .arg (file.errorString()));
        return;                                             //must return
    }
    file.close();

    SaveSceneAsCI3D (currentFileName);                      //Saves the scene as a CI3D file
    statusBar()->showMessage (tr("Scene saved"), 2000);     //Shows a message in the status bar
}

/// <summary>
/// Slot method called to create an operation
/// </summary>
/// <param name="status"> An integer that identifies the status to set for all 3D views </param>
/// <param name="opID"> An integer that identifies the operation to create </param>
void CIGui::MainWindow::SetViewsStatus (int status, int opID) {
    //Computing the feedback position
    switch (status) {
        case View::PRIMITIVES_TRANSLATION:            //TRANSLATION
            View::Feedback_Translation.ComputeFeedbackPosition (scene);
            break;

        case View::PRIMITIVES_SCALING:                //SCALING
            View::Feedback_Scaling.ComputeFeedbackPosition (scene);
            break;

        case View::PRIMITIVES_ROTATION:               //ROTATION
            View::Feedback_Rotation.ComputeFeedbackPosition (scene);
            break;
    }

    //Setting the interactive action and the current operation ID for all 3D views
    for (unsigned short i = 0; i < views.size(); i++)
        if (status != View::MESH_CREATION ||                        //If is not a status of geometry creation
            views[i]->GetCameraType() != Camera::USER) {            //Or if the current view camera is not of type Camera::USER (3D view)
                views[i]->SetCurrentOperationID (opID);             //sets the current operation ID of the operation to do
                views[i]->SetInteractiveAction (status);            //sets the current interactive action
        }
        else
            views[i]->SetInteractiveAction (View::NONE);
}

/// <summary>
/// Slot method called to undo the last user action
/// </summary>
void CIGui::MainWindow::UndoOperation() {
    scene.saved = false;

    operationManager.UndoOperation();

    //Enabling/Disabling the undo action
    undoAct->setEnabled (operationManager.undoOps.size() != 0);

    //Enabling/Disabling the redo action
    redoAct->setEnabled (operationManager.redoOps.size() != 0);
}

/// <summary>
/// Slot method called to redo the last user action
/// </summary>
void CIGui::MainWindow::RedoOperation() {
    scene.saved = false;

    operationManager.RedoOperation();

    //Enabling/Disabling the undo action
    undoAct->setEnabled (operationManager.undoOps.size() != 0);

    //Enabling/Disabling the redo action
    redoAct->setEnabled (operationManager.redoOps.size() != 0);
}

/// <summary>
/// Slot method called to delete the selected primitives
/// </summary>
void CIGui::MainWindow::DeleteOperation() {
    scene.saved = false;

    operationManager.DoOperation (OperationManager::DELETE_SELECTION);

    //Disabling the delete action
    deleteAct->setDisabled (true);

    //Disabling the redo action
    redoAct->setEnabled (false);
}

/// <summary>
/// Slot method called to duplicate the selected primitives
/// </summary>
void CIGui::MainWindow::DuplicateOperation() {
    operationManager.DoOperation (OperationManager::DUPLICATE_SELECTION);

    //Disabling the redo action
    redoAct->setEnabled (false);
}

/// <summary>
/// Slot method called to execute the operation identified by opID
/// </summary>
/// <param name="opID"> The ID of the operation to execute </param>
void CIGui::MainWindow::DoOperation (int opID) {
    //Executing the operation
    operationManager.DoOperation (opID);

    //Disabling the redo action
    redoAct->setEnabled (false);
}

/// <summary>
/// Slot method called to updates the 3D views
/// </summary>
void CIGui::MainWindow::UpdateViews() {
    switch (views[0]->GetFeedbackMode()) {
        case View::FEEDBACK_TRANSLATION:            //TRANSLATION
            View::Feedback_Translation.ComputeFeedbackPosition (scene);
            break;

        case View::FEEDBACK_ROTATION:               //ROTATION
            View::Feedback_Rotation.ComputeFeedbackPosition (scene);
            break;

        case View::FEEDBACK_SCALING:                //SCALING
            View::Feedback_Scaling.ComputeFeedbackPosition (scene);
            break;
    }

    for (unsigned short i = 0; i < views.size(); i++) {
        views[i]->updateGL();
    }
}
/***************************************************************************************************************
******************************************* endregion Public SLOTS *********************************************
****************************************************************************************************************/









///<************************************************************************************************************>
///<**************************************** region Utility Methods ********************************************>
///<************************************************************************************************************>

/// <summary>
/// Method called to create the actions
/// </summary>
void CIGui::MainWindow::CreateActions() {                            //TODO -> Look at actions again
    aboutAct = new QAction (tr ("&About"), this);
    aboutAct->setStatusTip (tr ("Show the application's About box"));
    connect (aboutAct, SIGNAL (triggered()), this, SLOT (About()));

    newAct = new QAction (QIcon (IMAGES_FOLDER + "new.png"), tr ("&New..."), this);
    newAct->setShortcuts (QKeySequence::New);
    newAct->setStatusTip (tr ("Create new scene"));
    connect (newAct, SIGNAL (triggered()), this, SLOT (New()));

    openAct = new QAction (QIcon (IMAGES_FOLDER + "open.png"), tr ("&Open..."), this);
    openAct->setShortcuts (QKeySequence::Open);
    openAct->setStatusTip (tr ("Open a saved scene"));
    connect (openAct, SIGNAL (triggered()), this, SLOT (Open()));

    saveAct = new QAction (QIcon (IMAGES_FOLDER + "save.png"), tr ("&Save..."), this);
    saveAct->setShortcuts (QKeySequence::Save);
    saveAct->setStatusTip (tr ("Save the current scene"));
    connect (saveAct, SIGNAL (triggered()), this, SLOT (Save()));

    saveAsAct = new QAction(tr ("&Save As..."), this);
    saveAsAct->setShortcuts (QKeySequence::SaveAs);
    saveAsAct->setStatusTip (tr ("Save the current scene"));
    connect (saveAsAct, SIGNAL (triggered()), this, SLOT (SaveAs()));

    quitAct = new QAction (tr ("&Quit"), this);
    quitAct->setShortcut (tr ("Ctrl+Q"));
    quitAct->setStatusTip (tr ("Quit the application"));
    connect (quitAct, SIGNAL (triggered()), this, SLOT (close()));

    undoAct = new QAction (QIcon (IMAGES_FOLDER + "undo.png"), tr ("&Undo..."), this);
    undoAct->setShortcuts (QKeySequence::Undo);
    undoAct->setStatusTip (tr ("Undo the last editing action"));
    undoAct->setDisabled (true);
    connect (undoAct, SIGNAL (triggered()), this, SLOT (UndoOperation()));

    redoAct = new QAction (QIcon (IMAGES_FOLDER + "redo.png"), tr ("&Redo..."), this);
    redoAct->setShortcuts (QKeySequence::Redo);
    redoAct->setStatusTip (tr ("Redo the last editing action"));
    redoAct->setDisabled (true);
    connect (redoAct, SIGNAL (triggered()), this, SLOT (RedoOperation()));

    deleteAct = new QAction (QIcon (IMAGES_FOLDER + "delete.png"), tr ("&Delete..."), this);
    deleteAct->setShortcuts (QKeySequence::Delete);
    deleteAct->setStatusTip (tr ("Delete the selected primitives"));
    deleteAct->setDisabled (true);
    connect (deleteAct, SIGNAL (triggered()), this, SLOT (DeleteOperation()));

    duplicateAct = new QAction (QIcon (IMAGES_FOLDER + "duplicate.png"), tr ("&Duplicate..."), this);
    duplicateAct->setShortcut (QKeySequence( tr("Ctrl+D")));
    duplicateAct->setStatusTip (tr ("Duplicate the selected primitives"));
    duplicateAct->setDisabled (true);
    connect (duplicateAct, SIGNAL (triggered()), this, SLOT (DuplicateOperation()));

    //Select-All-Act
    selectAllAct = operationManager.CreateAction(IMAGES_FOLDER + "select_all.png",              //Icon path
                                                   tr ("Select All"),                           //Tooltip
                                                   tr ("Alt+4"),                                //Shortcut
                                                   this,                                        //parent
                                                   View::NONE,                                  //The views status when clicked
                                                   OperationManager::SELECT_ALL);               //The id of the operation associated
    selectAllAct->setCheckable (false);
    connect (selectAllAct, SIGNAL (triggered (int)), this, SLOT (DoOperation (int)));

    //Deselect-All-Act
    deselectAllAct = operationManager.CreateAction(IMAGES_FOLDER + "deselect_all.png",          //Icon path
                                                   tr ("Deselect All"),                         //Tooltip
                                                   tr ("Alt+5"),                                //Shortcut
                                                   this,                                        //parent
                                                   View::NONE,                                  //The views status when clicked
                                                   OperationManager::DESELECT_ALL);             //The id of the operation associated
    deselectAllAct->setCheckable (false);
    connect (deselectAllAct, SIGNAL (triggered (int)), this, SLOT (DoOperation (int)));

    //Invert-Selection-Act
    invertSelectionAct = operationManager.CreateAction(IMAGES_FOLDER + "invert_selection.png",      //Icon path
                                                   tr ("Invert Selection"),                         //Tooltip
                                                   tr ("Alt+6"),                                    //Shortcut
                                                   this,                                            //parent
                                                   View::NONE,                                      //The views status when clicked
                                                   OperationManager::INVERT_SELECTION);             //The id of the operation associated
    invertSelectionAct->setCheckable (false);
    connect (invertSelectionAct, SIGNAL (triggered (int)), this, SLOT (DoOperation (int)));

    //Hide-Selection-Act
    hideAct = operationManager.CreateAction(IMAGES_FOLDER + "hide.png",             //Icon path
                                                   tr ("Hide Selection"),           //Tooltip
                                                   tr ("Alt+7"),                    //Shortcut
                                                   this,                            //parent
                                                   View::NONE,                      //The views status when clicked
                                                   OperationManager::HIDE);         //The id of the operation associated
    hideAct->setCheckable (false);
    connect (hideAct, SIGNAL (triggered (int)), this, SLOT (DoOperation (int)));

    //Unhide-All-Act
    unhideAct = operationManager.CreateAction(IMAGES_FOLDER + "unhide.png",         //Icon path
                                                   tr ("Unhide All"),               //Tooltip
                                                   tr ("Alt+8"),                    //Shortcut
                                                   this,                            //parent
                                                   View::NONE,                      //The views status when clicked
                                                   OperationManager::UNHIDE);       //The id of the operation associated
    unhideAct->setCheckable (false);
    connect (unhideAct, SIGNAL (triggered (int)), this, SLOT (DoOperation (int)));



  /* Operations'Actions */
    operationsActionGroup = new QActionGroup (this);
    //Normal-Interaction
    cameraControlAct = operationManager.CreateAction(IMAGES_FOLDER + "arrow.png",                   //Icon path
                                                   tr ("Camera Control"),                           //Tooltip
                                                   tr ("s"),                                        //Shortcut
                                                   this,                                            //parent
                                                   View::NONE);                                     //The views status when clicked
    cameraControlAct->setChecked (true);
    connect (cameraControlAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (cameraControlAct);

    //separator
    operationsActionGroup->addSeparator();      //Adds a separator between selection and creation actions


    //Select-Vertices-Operation
    selectVerticesAct = operationManager.CreateAction(IMAGES_FOLDER + "select_vertices.png",        //Icon path
                                                   tr ("Select Vertices"),                          //Tooltip
                                                   tr ("Alt+1"),                                    //Shortcut
                                                   this,                                            //parent
                                                   View::SELECTION,                                 //The views status when clicked
                                                   OperationManager::SELECT_VERTICES);              //The id of the operation associated
    connect (selectVerticesAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (selectVerticesAct);


    //Select-Faces-Operation
    selectFacesAct = operationManager.CreateAction(IMAGES_FOLDER + "select_faces.png",          //Icon path
                                                   tr ("Select Faces"),                         //Tooltip
                                                   tr ("Alt+2"),                                //Shortcut
                                                   this,                                        //parent
                                                   View::SELECTION,                             //The views status when clicked
                                                   OperationManager::SELECT_FACES);             //The id of the operation associated
    connect (selectFacesAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (selectFacesAct);


    //Select-Geoemtries-Operation
    selectGeometriesAct = operationManager.CreateAction(IMAGES_FOLDER + "select_geometries.png",        //Icon path
                                                   tr ("Select Geometries"),                            //Tooltip
                                                   tr ("Alt+3"),                                        //Shortcut
                                                   this,                                                //parent
                                                   View::SELECTION,                                     //The views status when clicked
                                                   OperationManager::SELECT_GEOMETRIES);                //The id of the operation associated
    connect (selectGeometriesAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (selectGeometriesAct);

    //separator
    operationsActionGroup->addSeparator();      //Adds a separator between selection and transformation actions


    //Translate-Operation
    translateAct = operationManager.CreateAction(IMAGES_FOLDER + "translate.png",           //Icon path
                                                   tr ("Translate Selection"),              //Tooltip
                                                   tr ("q"),                                //Shortcut
                                                   this,                                    //parent
                                                   View::PRIMITIVES_TRANSLATION,            //The views status when clicked
                                                   OperationManager::TRANSLATE);            //The id of the operation associated
    connect (translateAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (translateAct);


    //Scale-Operation
    scaleAct = operationManager.CreateAction(IMAGES_FOLDER + "scale.png",                   //Icon path
                                                   tr ("Scale Selection"),                  //Tooltip
                                                   tr ("w"),                                //Shortcut
                                                   this,                                    //parent
                                                   View::PRIMITIVES_SCALING,                //The views status when clicked
                                                   OperationManager::SCALE);                //The id of the operation associated
    connect (scaleAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (scaleAct);

    //Rotate-Operation
    rotateAct = operationManager.CreateAction(IMAGES_FOLDER + "rotate.png",                 //Icon path
                                                   tr ("Rotate Selection"),                 //Tooltip
                                                   tr ("r"),                                //Shortcut
                                                   this,                                    //parent
                                                   View::PRIMITIVES_ROTATION,               //The views status when clicked
                                                   OperationManager::ROTATE);               //The id of the operation associated
    connect (rotateAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (rotateAct);

    //Extrude-Operation
    extrudeAct = operationManager.CreateAction(IMAGES_FOLDER + "extrude.png",               //Icon path
                                                   tr ("Extrude Selection"),                //Tooltip
                                                   tr ("e"),                                //Shortcut
                                                   this,                                    //parent
                                                   View::PRIMITIVES_EXTRUSION,              //The views status when clicked
                                                   OperationManager::EXTRUDE);              //The id of the operation associated
    connect (extrudeAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (extrudeAct);

    //separator
    operationsActionGroup->addSeparator();      //Adds a separator between transformation and creation actions



    //Create-Vertex-Operation
    createVertexAct = operationManager.CreateAction(IMAGES_FOLDER + "vertex.png",             //Icon path
                                                   tr ("Create a Vertex"),                    //Tooltip
                                                   tr ("Ctrl+1"),                             //Shortcut
                                                   this,                                      //parent
                                                   View::MESH_CREATION,                       //The views status when clicked
                                                   OperationManager::CREATE_VERTEX);          //The id of the operation associated
    connect (createVertexAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (createVertexAct);


    //Create-Triangle-Operation
    createTriangleAct = operationManager.CreateAction(IMAGES_FOLDER + "triangle.png",         //Icon path
                                                   tr ("Create a Triangle"),                  //Tooltip
                                                   tr ("Ctrl+2"),                             //Shortcut
                                                   this,                                      //parent
                                                   View::MESH_CREATION,                       //The views status when clicked
                                                   OperationManager::CREATE_TRIANGLE);        //The id of the operation associated
    connect (createTriangleAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (createTriangleAct);


    ////Create-Triangle-Strip-Operation
    //createTriangleStripAct = operationManager.CreateAction(IMAGES_FOLDER + "triangle_strip.png",        //Icon path
    //                                               tr ("Create a Triangle Strip"),                      //Tooltip
    //                                               tr ("Ctrl+9"),                                       //Shortcut
    //                                               this,                                                //parent
    //                                               View::MESH_CREATION,                                 //The views status when clicked
    //                                               OperationManager::CREATE_TRIANGLE_STRIP);            //The id of the operation associated
    //connect (createTriangleStripAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    //operationsActionGroup->add (createTriangleStripAct);
    //

    //Create-Rectangle-Operation
    createRectangleAct = operationManager.CreateAction(IMAGES_FOLDER + "rectangle.png",         //Icon path
                                                   tr ("Create a Rectangle"),                   //Tooltip
                                                   tr ("Ctrl+3"),                               //Shortcut
                                                   this,                                        //parent
                                                   View::MESH_CREATION,                         //The views status when clicked
                                                   OperationManager::CREATE_RECTANGLE);         //The id of the operation associated
    connect (createRectangleAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (createRectangleAct);


    //Create-Cuboid-Operation
    createCuboidAct = operationManager.CreateAction(IMAGES_FOLDER + "cuboid.png",               //Icon path
                                                   tr ("Create a Cuboid"),                      //Tooltip
                                                   tr ("Ctrl+4"),                               //Shortcut
                                                   this,                                        //parent
                                                   View::MESH_CREATION,                         //The views status when clicked
                                                   OperationManager::CREATE_CUBOID);            //The id of the operation associated
    connect (createCuboidAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (createCuboidAct);


    //Create-Sphere-Operation
    createSphereAct = operationManager.CreateAction(IMAGES_FOLDER + "sphere.png",           //Icon path
                                                   tr ("Create a Sphere"),                  //Tooltip
                                                   tr ("Ctrl+5"),                           //Shortcut
                                                   this,                                    //parent
                                                   View::MESH_CREATION,                     //The views status when clicked
                                                   OperationManager::CREATE_SPHERE);        //The id of the operation associated
    connect (createSphereAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (createSphereAct);


    //Create-Cylinder-Operation
    createCylinderAct = operationManager.CreateAction(IMAGES_FOLDER + "cylinder.png",           //Icon path
                                                   tr ("Create a Cylinder"),                    //Tooltip
                                                   tr ("Ctrl+6"),                               //Shortcut
                                                   this,                                        //parent
                                                   View::MESH_CREATION,                         //The views status when clicked
                                                   OperationManager::CREATE_CYLINDER);          //The id of the operation associated
    connect (createCylinderAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (createCylinderAct);


    //Create-Cone-Operation
    createConeAct = operationManager.CreateAction(IMAGES_FOLDER + "cone.png",                   //Icon path
                                                   tr ("Create a Cone"),                        //Tooltip
                                                   tr ("Ctrl+7"),                               //Shortcut
                                                   this,                                        //parent
                                                   View::MESH_CREATION,                         //The views status when clicked
                                                   OperationManager::CREATE_CONE);              //The id of the operation associated
    connect (createConeAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (createConeAct);


    //Create-Torus-Operation
    createTorusAct = operationManager.CreateAction(IMAGES_FOLDER + "torus.png",                 //Icon path
                                                   tr ("Create a Torus"),                       //Tooltip
                                                   tr ("Ctrl+8"),                               //Shortcut
                                                   this,                                        //parent
                                                   View::MESH_CREATION,                         //The views status when clicked
                                                   OperationManager::CREATE_TORUS);             //The id of the operation associated
    connect (createTorusAct, SIGNAL (triggered (int, int)), this, SLOT (SetViewsStatus (int, int)));
    operationsActionGroup->add (createTorusAct);

    translateAct->setDisabled (true);
    scaleAct->setDisabled (true);
    rotateAct->setDisabled (true);
    extrudeAct->setDisabled (true);
}

/// <summary>
/// Method called to create the window's content
/// </summary>
void CIGui::MainWindow::CreateContent() {
    content = new QWidget (this);               //The window's content widget
    setCentralWidget (content);                 //Sets the content widget as the main window central widget
    content->setLayout (contentLayout);         //Sets the content layout as main layout for the content widget
}

/// <summary>
/// Method called to create the window's layouts
/// </summary>
void CIGui::MainWindow::CreateLayouts() {
    contentLayout = new QHBoxLayout();                  //The window's content layout
}

/// <summary>
/// Method called to create the window's menus
/// </summary>
void CIGui::MainWindow::CreateMenus() {                                        //TODO -> Look at menus again
    //Adding menus to the window's menu bar
    fileMenu = menuBar()->addMenu (tr ("&File"));
    fileMenu->addAction (newAct);
    fileMenu->addAction (openAct);
    fileMenu->addAction (saveAct);
    fileMenu->addAction (saveAsAct);

    fileMenu->addSeparator();

    fileMenu->addAction (quitAct);

    editMenu = menuBar()->addMenu (tr ("&Edit"));
    editMenu->addAction (undoAct);
    editMenu->addAction (redoAct);
    editMenu->addAction (deleteAct);
    editMenu->addAction (duplicateAct);

    editMenu->addSeparator();

    editMenu->addAction (selectAllAct);
    editMenu->addAction (deselectAllAct);
    editMenu->addAction (invertSelectionAct);

    editMenu->addSeparator();

    editMenu->addAction (hideAct);
    editMenu->addAction (unhideAct);

    viewMenu = 0;//menuBar()->addMenu (tr ("&View"));

    toolsMenu = menuBar()->addMenu (tr ("&Tools"));
    toolsMenu->addActions (operationsActionGroup->actions());

    menuBar()->addSeparator();

    helpMenu = menuBar()->addMenu (tr ("&Help"));
    helpMenu->addAction (aboutAct);
}

/// <summary>
/// Method called to create the window's status bar
/// </summary>
void CIGui::MainWindow::CreateStatusBar() {
    statusBar()->showMessage (tr ("Ready"));        //Sets the initial status as "Ready"
}

/// <summary>
/// Method called to create the window's toolbars
/// </summary>
void CIGui::MainWindow::CreateToolbars() {                                        //TODO -> Look at toolbars again
    operationsToolBar = new QToolBar (tr ("Tools"));
    addToolBar (Qt::LeftToolBarArea, operationsToolBar);
    operationsToolBar->addActions (operationsActionGroup->actions());
    operationsToolBar->setIconSize (QSize (30,30));

    editToolBar = addToolBar (tr ("Edit"));
    editToolBar->addAction (newAct);
    editToolBar->addAction (openAct);
    editToolBar->addAction (saveAct);
    editToolBar->addSeparator();
    editToolBar->addAction (undoAct);
    editToolBar->addAction (redoAct);
    editToolBar->addAction (deleteAct);
    editToolBar->addAction (duplicateAct);

    editToolBar->addSeparator();

    editToolBar->addAction (selectAllAct);
    editToolBar->addAction (deselectAllAct);
    editToolBar->addAction (invertSelectionAct);

    editToolBar->addSeparator();

    editToolBar->addAction (hideAct);
    editToolBar->addAction (unhideAct);

    editToolBar->setIconSize (QSize (28,28));
}

/// <summary>
/// Method called to create the controls tab
/// </summary>
void CIGui::MainWindow::CreateControlsTab() {                                    //TODO -> Look at controls again
    controls = new QTabWidget (content);
    controls->setMaximumSize (270, 1800);
    controls->setMinimumSize (270, 300);
    contentLayout->addWidget (controls);

    //Setting controls style sheet
    controls->setStyleSheet ("QWidget {"
                                "border-radius: 10px;"
                             "}"
                             );

    //controls->setTabsClosable (true);
    //connect (controls, SIGNAL (tabCloseRequested(int)), this, SLOT (RemoveTab(int)));
    //controls->setMovable (true);
}

/// <summary>
/// Method called to create the modeling controls
/// </summary>
void CIGui::MainWindow::CreateModelingControls() {
    modelingControls = new QWidget (controls);
    controls->addTab (modelingControls, "Modeling");
    modelingControls->setStyleSheet ("QFrame {"
                                         "border: 0px;"
                                         "border-radius: 0px;"
                                         "background: rgba(0,0,0,0);"
                                     "}"

                                     "QToolBox::tab {"
                                         "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
                                                                     "stop: 0 #E1E1E1, stop: 0.4 #DDDDDD,"
                                                                     "stop: 0.5 #D8D8D8, stop: 1.0 #D3D3D3);"
                                         "border-radius: 5px;"
                                         "color: darkgray;"
                                         "text-align: center;"
                                         "font-family: sans-serif;"
                                         "font-size: 8pt;"
                                      "}"

                                      "QToolBox::tab:selected {"
                                         "font-family: sans-serif;"
                                         "font: italic;"
                                         "color: white;"
                                      "}"
                                     );

//     QString TOOL_BOX_PAGE_STYLE_SHEET =

    QButtonGroup* buttonGroup = new QButtonGroup();


/****************************************** Selection Tool Box page **********************************************/
    QWidget* selectionPage = new QWidget();
    selectionPage->setStyleSheet (TOOL_BOX_PAGE_STYLE_SHEET);
    QGridLayout* selectionLayout = new QGridLayout();
    selectionPage->setLayout (selectionLayout);
    //selectionLayout->addWidget (ToolButtonWidget (buttonGroup, cameraControlAct) , 0, 0, Qt::AlignCenter);
    ToolButtonWidget (buttonGroup, cameraControlAct);
    selectionLayout->addWidget (ToolButtonWidget (buttonGroup, selectVerticesAct)  , 0, 0, Qt::AlignCenter);
    selectionLayout->addWidget (ToolButtonWidget (buttonGroup, selectAllAct)       , 0, 1, Qt::AlignCenter);
    selectionLayout->addWidget (ToolButtonWidget (buttonGroup, selectFacesAct)     , 1, 0, Qt::AlignCenter);
    selectionLayout->addWidget (ToolButtonWidget (buttonGroup, deselectAllAct)     , 1, 1, Qt::AlignCenter);
    selectionLayout->addWidget (ToolButtonWidget (buttonGroup, selectGeometriesAct), 2, 0, Qt::AlignCenter);
    selectionLayout->addWidget (ToolButtonWidget (buttonGroup, invertSelectionAct) , 2, 1, Qt::AlignCenter);
    selectionLayout->addWidget (ToolButtonWidget (buttonGroup, hideAct)            , 3, 0, Qt::AlignCenter);
    selectionLayout->addWidget (ToolButtonWidget (buttonGroup, unhideAct)          , 3, 1, Qt::AlignCenter);
    selectionLayout->addItem (new QSpacerItem (100, 100, QSizePolicy::Minimum, QSizePolicy::Expanding), 5, 0);

    //Creating the vertices selection properties widget
    PropertyGroup* verticesProperties = new PropertyGroup ((ActionOpCreation*)selectVerticesAct, "Selection");
    verticesProperties->AddIgnoreBackfacesProperty();
    selectionLayout->addWidget (verticesProperties, 6, 0, 1, 0, Qt::AlignCenter);

    //Creating the faces selection properties widget
    PropertyGroup* facesProperties = new PropertyGroup ((ActionOpCreation*)selectFacesAct, "Selection");
    facesProperties->AddIgnoreBackfacesProperty();
    selectionLayout->addWidget (facesProperties, 7, 0, 1, 0, Qt::AlignCenter);

    //Creating the geometries selection properties widget
    PropertyGroup* geometriesProperties = new PropertyGroup ((ActionOpCreation*)selectGeometriesAct, "Selection");
    geometriesProperties->AddIgnoreBackfacesProperty();
    selectionLayout->addWidget (geometriesProperties, 8, 0, 1, 0, Qt::AlignCenter);
/******************************************************************************************************************/



/*************************************** Transformation Tool Box page **********************************************/
    QWidget* transformationPage = new QWidget();
    transformationPage->setStyleSheet (TOOL_BOX_PAGE_STYLE_SHEET);
    QGridLayout* transformationLayout = new QGridLayout();
    transformationPage->setLayout (transformationLayout);
    transformationLayout->addWidget (ToolButtonWidget (buttonGroup, translateAct), 0, 0, Qt::AlignCenter);
    transformationLayout->addWidget (ToolButtonWidget (buttonGroup, scaleAct), 0, 1, Qt::AlignCenter);
    transformationLayout->addWidget (ToolButtonWidget (buttonGroup, rotateAct), 1, 0, Qt::AlignCenter);
    transformationLayout->addWidget (ToolButtonWidget (buttonGroup, extrudeAct), 1, 1, Qt::AlignCenter);
    transformationLayout->addItem (new QSpacerItem (100, 100, QSizePolicy::Minimum, QSizePolicy::Expanding), 2, 0);

    //Creating the translate properties widget
    PropertyGroup* translateProperties = TransformationPropertyGroup ((ActionOpCreation*)translateAct, "Translate", "0.0");
    connect (translateProperties, SIGNAL (OperationRequest (int)), this, SLOT( DoOperation (int)));
    connect (translateProperties, SIGNAL (PropertyChanged()), this, SLOT (UpdateViews()));

    //Creating the scale properties widget
    PropertyGroup* scaleProperties = TransformationPropertyGroup ((ActionOpCreation*)scaleAct, "Scale", "1.0");
    scaleProperties->AddReferencePointProperties();
    connect (scaleProperties, SIGNAL (OperationRequest (int)), this, SLOT( DoOperation (int)));
    connect (scaleProperties, SIGNAL (PropertyChanged()), this, SLOT (UpdateViews()));

    //Creating the rotate properties widget
    PropertyGroup* rotateProperties = TransformationPropertyGroup ((ActionOpCreation*)rotateAct, "Rotate", "0.0");
    rotateProperties->AddReferencePointProperties();
    connect (rotateProperties, SIGNAL (OperationRequest (int)), this, SLOT( DoOperation (int)));
    connect (rotateProperties, SIGNAL (PropertyChanged()), this, SLOT (UpdateViews()));

    //Creating the extrude properties widget
    PropertyGroup* extrudeProperties = TransformationPropertyGroup ((ActionOpCreation*)extrudeAct, "Extrude", "0.0");
    connect (extrudeProperties, SIGNAL (OperationRequest (int)), this, SLOT( DoOperation (int)));
    connect (extrudeProperties, SIGNAL (PropertyChanged()), this, SLOT (UpdateViews()));

    //Adding the transformation properties widgets
    transformationLayout->addWidget (translateProperties, 3, 0, 1, 0, Qt::AlignCenter);
    transformationLayout->addWidget (scaleProperties, 4, 0, 1, 0, Qt::AlignCenter);
    transformationLayout->addWidget (rotateProperties, 5, 0, 1, 0, Qt::AlignCenter);
    transformationLayout->addWidget (extrudeProperties, 6, 0, 1, 0, Qt::AlignCenter);
/******************************************************************************************************************/




/*************************************** Primitives Tool Box page *************************************************/
    QWidget* primitivesPage = new QWidget();
    primitivesPage->setStyleSheet (TOOL_BOX_PAGE_STYLE_SHEET);
    QGridLayout* primitivesLayout = new QGridLayout();
    primitivesPage->setLayout (primitivesLayout);
    primitivesLayout->addWidget (ToolButtonWidget (buttonGroup, createVertexAct), 0, 0, Qt::AlignCenter);
    primitivesLayout->addWidget (ToolButtonWidget (buttonGroup, createTriangleAct), 0, 1, Qt::AlignCenter);
    primitivesLayout->addWidget (ToolButtonWidget (buttonGroup, createRectangleAct), 1, 0, Qt::AlignCenter);
    primitivesLayout->addWidget (ToolButtonWidget (buttonGroup, createCuboidAct), 1, 1, Qt::AlignCenter);
    primitivesLayout->addWidget (ToolButtonWidget (buttonGroup, createSphereAct), 2, 0, Qt::AlignCenter);
    primitivesLayout->addWidget (ToolButtonWidget (buttonGroup, createCylinderAct), 2, 1, Qt::AlignCenter);
    primitivesLayout->addWidget (ToolButtonWidget (buttonGroup, createConeAct), 3, 0, Qt::AlignCenter);
    primitivesLayout->addWidget (ToolButtonWidget (buttonGroup, createTorusAct), 3, 1, Qt::AlignCenter);
    primitivesLayout->addItem (new QSpacerItem (100, 100, QSizePolicy::Minimum, QSizePolicy::Expanding), 4, 0);

    //Creating the sphere properties widget
    PropertyGroup* sphereProperties = new PropertyGroup ((ActionOpCreation*)createSphereAct, "Sphere");
    sphereProperties->AddCreationProperties ("10", "10");
    primitivesLayout->addWidget (sphereProperties, 5, 0, 1, 0, Qt::AlignCenter);

    //Creating the cylinder properties widget
    PropertyGroup* cylinderProperties = new PropertyGroup ((ActionOpCreation*)createCylinderAct, "Cylinder");
    cylinderProperties->AddCreationProperties ("6", "12");
    primitivesLayout->addWidget (cylinderProperties, 6, 0, 1, 0, Qt::AlignCenter);

    //Creating the cone properties widget
    PropertyGroup* coneProperties = new PropertyGroup ((ActionOpCreation*)createConeAct, "Cone");
    coneProperties->AddCreationProperties ("6", "12");
    primitivesLayout->addWidget (coneProperties, 7, 0, 1, 0, Qt::AlignCenter);

    //Creating the torus properties widget
    PropertyGroup* torusProperties = new PropertyGroup ((ActionOpCreation*)createTorusAct, "Torus");
    torusProperties->AddCreationProperties ("12", "12");
    torusProperties->AddThicknessProperty ("2.0");
    primitivesLayout->addWidget (torusProperties, 8, 0, 1, 0, Qt::AlignCenter);
/******************************************************************************************************************/

    //Creating the tool box
    QToolBox* toolBox = new QToolBox();
    toolBox->addItem (selectionPage, tr("Selection"));
    toolBox->addItem (transformationPage, tr("Transformation"));
    toolBox->addItem (primitivesPage, tr("Primitives"));
    toolBox->setCurrentIndex (2);

    //Adding the toolbox
    QGridLayout* mainLayout = new QGridLayout();
    modelingControls->setLayout (mainLayout);
    mainLayout->addWidget (toolBox);
}

/// <summary>
/// Method called to create the materials'controls
/// </summary>
void CIGui::MainWindow::CreateMaterialsControls() {
    materialsControls = new QWidget();
    //controls->addTab (materialsControls, "Groups and Materials");

}

/// <summary>
/// Method called to create and get a widget containing a tool button
/// according to the action received as input and inserting it in the button group
/// </summary>
/// <param name="buttonGroup"> The button group that will contain the new tool button </param>
/// <param name="act"> The action associated to the new tool button </param>
QWidget* CIGui::MainWindow::ToolButtonWidget (QButtonGroup* buttonGroup, QAction* act) {
    QToolButton* button = new QToolButton();
    button->setDefaultAction (act);
    button->setIconSize (QSize (50, 50));
    button->setCheckable(true);

    buttonGroup->addButton (button);

    QGridLayout* layout = new QGridLayout;
    layout->addWidget(button, 0, 0, Qt::AlignHCenter);
    layout->addWidget(new QLabel (act->text()), 1, 0, Qt::AlignCenter);

    QWidget* widget = new QWidget;
    widget->setLayout (layout);
    widget->setMinimumWidth (fontMetrics().width (act->text())-10);

    return widget;
}

/// <summary>
/// Method called to create and get a widget containing
/// the properties for a transformation operation
/// </summary>
/// <param name="act"> The action associated </param>
/// <param name="name"> The name of the transformation </param>
/// <param name="default_value"> The default value for the x, y and z line edit objects </param>
CIGui::PropertyGroup* CIGui::MainWindow::TransformationPropertyGroup (CIOps::ActionOpCreation* act, QString name, QString default_value) {
    PropertyGroup* transformationProperties = new PropertyGroup (act, name);

    transformationProperties->Add_X_Y_Z_Properties (default_value);

    return transformationProperties;
}


/// <summary>
/// Method called to create and get a widget containing
/// the radio buttons for a transformation operation
/// </summary>
QWidget* CIGui::MainWindow::TransformationRadioButtons() {
    QWidget* radioButtons = new QWidget();
    QVBoxLayout* radioButtonsLayout = new QVBoxLayout();
    radioButtons->setLayout (radioButtonsLayout);

    QRadioButton* CenterOfMass = new QRadioButton ("Center Of Mass");
    CenterOfMass->setName ("CenterOfMass");
    CenterOfMass->setChecked (true);
    radioButtonsLayout->addWidget (CenterOfMass);

    QRadioButton* Origin = new QRadioButton ("Origin");
    Origin->setName ("Origin");
    radioButtonsLayout->addWidget (Origin);

    return radioButtons;
}

/// <summary>
/// Method called to create the gl view
/// </summary>
void CIGui::MainWindow::CreateViews() {
    //Creating views
    views[0] = new View (Camera::TOP, scene, operationManager);
    views[0]->setSizePolicy (QSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding));
    views[0]->setStatusTip ("Ready");

    views[1] = new View (Camera::FRONT, scene, operationManager);
    views[1]->setSizePolicy (QSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding));
    views[1]->setStatusTip ("Ready");

    views[2] = new View (Camera::RIGHT, scene, operationManager);
    views[2]->setSizePolicy (QSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding));
    views[2]->setStatusTip ("Ready");

    views[3] = new View (Camera::USER, scene, operationManager);
    views[3]->setSizePolicy (QSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding));
    views[3]->setStatusTip ("Ready");


    //Connecting views with undo and redo actions
    for (unsigned short i = 0; i < 4; i++) {
        connect (views[i], SIGNAL (OperationCompleted (bool)), undoAct, SLOT (setEnabled (bool)));
        connect (views[i], SIGNAL (OperationCompleted (bool)), redoAct, SLOT (setDisabled (bool)));
        connect (views[i], SIGNAL (PrimitivesSelected (bool)), deleteAct, SLOT (setEnabled (bool)));
        connect (views[i], SIGNAL (PrimitivesSelected (bool)), duplicateAct, SLOT (setEnabled (bool)));
        connect (views[i], SIGNAL (PrimitivesSelected (bool)), translateAct, SLOT (setEnabled (bool)));
        connect (views[i], SIGNAL (PrimitivesSelected (bool)), scaleAct, SLOT (setEnabled (bool)));
        connect (views[i], SIGNAL (PrimitivesSelected (bool)), extrudeAct, SLOT (setEnabled (bool)));
        connect (views[i], SIGNAL (PrimitivesSelected (bool)), rotateAct, SLOT (setEnabled (bool)));
    }

    //Creating the views container
    viewsContainer = new ViewsContainer (views, content);

    //Adding the views'container to the content layout
    contentLayout->addWidget (viewsContainer);
}

///// <summary>
///// Virtual method called whenever the widget receives an event
///// </summary>
///// <param name="e"> The event </param>
//bool CIGui::MainWindow::event (QEvent *e) {
//    //Executing the current operation requested
//    //operationManager.DoOperation();         //Executes the current operation
//
//    return QMainWindow::event (e);
//}

/// <summary>
/// Method called whenever the widget receives a close event
/// </summary>
/// <param name="e"> The close event </param>
void CIGui::MainWindow::closeEvent(QCloseEvent *e) {
    //QSettings settings("CreativeInteraction", "CI3D");
    //settings.setValue("geometry", saveGeometry());
    //settings.setValue("windowState", saveState());

    if (!(scene.saved)) {                                                       //If the current scene has not been saved
        int response = QMessageBox::question (0,                                //shows a message box, asking to the user if he want to save the scene
                                   "CI3D",
                                   "Do you want to save the current scene?",
                                   "Yes",
                                   "No",
                                   "Cancel",
                                   2);

        switch (response) {
            case 0: //Yes
                Save();             //if the user answer is Yes, saves the scene
                break;

            case 2: //Cancel
                e->setAccepted (false);
                return;             //if the user answer is Cancel, must return
        }
    }

    QMainWindow::closeEvent(e);
}

/// <summary>
/// Method called to save the scene description
/// </summary>
/// <param name="filename"> The name of the file to save the scene description </param>
void CIGui::MainWindow::SaveSceneAsCI3D (const char* filename) {
    const char* tab = "    ";

    ofstream out;
    out.open (filename);
    out.clear();
    out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        << "<!DOCTYPE Creative_Interaction_3D_version_1.0>\n"
        << "<CI3D version=\"1.0\">\n";

    out << tab << "<scene>\n"
        << tab << tab << "<library_geometries>\n";


    QProgressDialog dialog ("Please wait...", "Cancel", 0, 100, 0, Qt::FramelessWindowHint);
    dialog.setStyleSheet (GENERAL_BACKGROUND);//GENERAL_BORDER + "border-radius: 20px;" + GENERAL_BACKGROUND);

    //Creating a QFutureWatcher and connecting signals and slots with the dialog
    QFutureWatcher<void> futureWatcher;
    QObject::connect(&futureWatcher, SIGNAL(finished()), &dialog, SLOT(reset()));
    QObject::connect(&dialog, SIGNAL(canceled()), &futureWatcher, SLOT(cancel()));
    QObject::connect(&futureWatcher, SIGNAL(progressRangeChanged(int, int)), &dialog, SLOT(setRange(int, int)));
    QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &dialog, SLOT(setValue(int)));

    QVector<pair<Geometry*, ofstream* > > v;
    pair<Geometry*, ofstream* > pair;
    pair.second = &out;

    map<const char*, Geometry*>& geometries = scene.GetGeometries();
    map<const char*, Geometry*>::iterator it = geometries.begin();
    while (it != geometries.end()) {                        //For each geometry
        pair.first = it->second;
        v.push_back (pair);
        it++;
    }

    //Starting the computation
    futureWatcher.setFuture(QtConcurrent::map(v, MainWindow::SaveGeometryAsCI3D));

    //Displaying the dialog and starting the event loop
    dialog.exec();

    //Waiting for the saving completion
    futureWatcher.waitForFinished();



    out << tab << tab << "</library_geometries>\n"
        << tab << "</scene>\n";


    out << "</CI3D>\n";
    out.close();
    scene.saved = true;
}

/// <summary>
/// Static method called to save the geometry description
/// </summary>
/// <param name="pair"> A reference to a pair formed by
/// pointers to the geometry to save and to the output stream </param>
void CIGui::MainWindow::SaveGeometryAsCI3D (std::pair<Geometry*, std::ofstream*>& pair) {
    pair.first->SaveAsCI3D (*pair.second);
    //Geometry* g = pair.first;
    //ofstream& out = *pair.second;

    //string& name = g->GetName();
    //VertexLib& vertices = g->GetVertices();
    //FaceLib& faces = g->GetFaces();

    //const char* tab = "    ";
    //stringstream stream;

    //stream << tab << tab << tab << "<geometry name=\"" << name.c_str() << "\">\n";

    //stream << tab << tab << tab << tab << "<mesh>\n";

    //stream << tab << tab << tab << tab << tab << "<vertices size=\"" << vertices.size() << "\">\n";

    //map<Vertex*,int> index;
    //Vertex* v;

    //for (int i=0; i<vertices.size(); i++) {         //For each vertex
    //    v = vertices[i];

    //    stream << tab << tab << tab << tab << tab << tab << "<v x=\"" << v->x
    //                                                     << "\" y=\"" << v->y
    //                                                     << "\" z=\"" << v->z
    //                                                     << "\"/>\n";
    //    index[v] = i;
    //}

    //stream << tab << tab << tab << tab << tab << "</vertices>\n";

    //stream << tab << tab << tab << tab << tab << "<faces size=\"" << faces.size() << "\">\n";

    //Face* f;

    //for (int i=0; i<faces.size(); i++) {                                    //For each face
    //    f = faces[i];

    //    stream << tab << tab << tab << tab << tab << tab << "<f size=\"" << f->vertices.size() << "\">\n";

    //    stream << tab << tab << tab << tab << tab << tab << tab << "<v_indices>";

    //    for (int j=0; j<f->vertices.size(); j++)                        //For each vertex of the face, saves the index of the vertex
    //        stream << index[f->vertices[j]] << " ";
    //
    //    stream << "</v_indices>\n";
    //
    //    stream << tab << tab << tab << tab << tab << tab << "</f>\n";
    //}

    //stream << tab << tab << tab << tab << tab << "</faces>\n";

    //stream << tab << tab << tab << tab << "</mesh>\n";

    //stream << tab << tab << tab << "</geometry>\n";
    //
    //out << stream.rdbuf();
}

/// <summary>
/// Method called to load a scene
/// </summary>
/// <param name="fileName"> The name of the file to load a scene </param>
bool CIGui::MainWindow::LoadSceneFromCI3D (const char* fileName) {
    CI3DHandler handler (scene);
    QXmlSimpleReader reader;
    reader.setContentHandler (&handler);
    reader.setErrorHandler (&handler);

    QFile file (fileName);

    if (!file.open(QFile::ReadOnly | QFile::Text)) {
        QMessageBox::warning(0, tr("CI3D"),
                             tr("Cannot read file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
        return false;
    }

    QXmlInputSource xmlInputSource (&file);

    return (reader.parse (xmlInputSource));
}
/***************************************************************************************************************
***************************************** endregion Utility Methods ********************************************
****************************************************************************************************************/





///<************************************************************************************************************>
///<**************************************** region SAX XML Handler ********************************************>
///<************************************************************************************************************>

bool CIGui::MainWindow::CI3DHandler::startElement(const QString & /* namespaceURI */,
                               const QString & /* localName */,
                               const QString &qName,
                               const QXmlAttributes &attributes) {

    if (!metCI3DTag && qName != "CI3D") {
        errorStr = QObject::tr("The file is not a CI3D file.");
        return false;
    }

    if (qName == "CI3D") {
        QString version = attributes.value("version");
        if (version.isEmpty() || version != "1.0") {
            errorStr = QObject::tr("The file is not a CI3D version 1.0 file.");
            return false;
        }
        metCI3DTag = true;
    }
    else if (qName == "geometry") {
        geometryName = attributes.value("name");
        if (geometryName.isEmpty()) {
            errorStr = QObject::tr("A geometry has not a name.");
            return false;
        }
    }
    else if (qName == "mesh") {
        currentGeometry = new PolygonMesh (geometryName);
        scene.AddGeometry (currentGeometry);
    }
    else if (qName == "point_cloud") {
        currentGeometry = new PointCloud (geometryName);
        scene.AddGeometry (currentGeometry);
    }
    else if (qName == "v") {
        float x = attributes.value("x").toFloat();
        float y = attributes.value("y").toFloat();
        float z = attributes.value("z").toFloat();
        currentGeometry->GetVertices().push_back (new Vertex (x, y, z));
    }

    currentText.clear();
    return true;
}

bool CIGui::MainWindow::CI3DHandler::endElement(const QString & /* namespaceURI */,
                             const QString & /* localName */,
                             const QString &qName) {

    if (qName == "v_indices") {
        QStringList indices = currentText.split(' ');
        VertexLib& vertices = currentGeometry->GetVertices();
        VertexLib faceVertices;

        for (int i=0; i<indices.size()-1; i++) {
            faceVertices.push_back (vertices[indices[i].toInt()]);
        }
        Face* f = new Face (faceVertices);
        f->ComputeNormal();
        currentGeometry->AddFace (f);
    }
    else if (qName == "geometry") {
            currentGeometry->ComputeNormals();          //computes normals for the loaded geometry
    }
    return true;
}

bool CIGui::MainWindow::CI3DHandler::characters(const QString &str) {
    currentText += str;
    return true;
}

bool CIGui::MainWindow::CI3DHandler::fatalError(const QXmlParseException &exception) {
    QMessageBox::information (0, QObject::tr("CI3D"),
                             QObject::tr("Parse error at line %1, column %2:\n"
                                         "%3")
                             .arg(exception.lineNumber())
                             .arg(exception.columnNumber())
                             .arg(exception.message()));
    return false;
}

QString CIGui::MainWindow::CI3DHandler::errorString() const {
    return errorStr;
}
/***************************************************************************************************************
***************************************** endregion SAX XML Handler ********************************************
****************************************************************************************************************/




